﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ServiceStack.Redis;

using RedisKeyEditor;

namespace RedisTool
{
    public partial class MainForm : Form
    {
        IniFile ini = new IniFile("server.ini");
        public const string aesKey = "zhangbin17282430";

        public MainForm()
        {
            InitializeComponent();
        }

        private void refreshServer()
        {
            serverTreeView.Nodes.Clear();
            var sets = ini.getSections();
            serverTreeView.BeginUpdate();
            foreach(String name in sets)
            {
                TreeNode node = new TreeNode();
                node.Name = node.Text = name;
                node.ImageKey = node.SelectedImageKey = "server";
                serverTreeView.Nodes.Add(node);
            }
            serverTreeView.EndUpdate();
        }

        private void enableMenu(bool enable)
        {
            m_server_edit.Enabled = mc_server_edit.Enabled = enable;
            m_server_remove.Enabled = mc_server_remove.Enabled = enable;
            m_server_view.Enabled = mc_server_view.Enabled = enable;
        }

        private void connectServer(TreeNode node)
        {
            string host = ini.get(node.Text, "host");
            int port = ini.getInt(node.Text, "port");
            string encoding = ini.get(node.Text, "keyEncoding","UTF-8");
            string password = ini.get(node.Text, "password");
            if (!String.IsNullOrEmpty(password))
                password = AESKit.Decrypt(password, aesKey);
            try
            {
                serverTreeView.BeginUpdate();
                Server server = new Server();
                server.Name = node.Name;
                server.encoding = encoding;
                server.client = new RedisNativeClient(host, port, password);
                node.Tag = server;
                node.Text = node.Name + "(" + server.client.ServerVersion + ")";
                server.DbCount=int.Parse(Encoding.UTF8.GetString(server.client.ConfigGet("databases")[1]));
                for (int i = 0; i < server.DbCount; i++)
                {
                    ServerDb db = new ServerDb(server);
                    db.db = i;
                    db.Refresh();
                    db.KeyCount = server.client.DbSize;
                    TreeNode n = new TreeNode();
                    n.Tag = db;
                    n.Name = "db" + i;
                    n.Text = n.Name + "(" + db.KeyCount + ")";
                    n.ImageKey = n.SelectedImageKey = "db";
                    node.Nodes.Add(n);                    
                }
                node.Expand();
                serverTreeView.EndUpdate();
                foreach (TreeNode n in node.Nodes)
                    RefreshDbKey(n);
                //bw_serverKeys.RunWorkerAsync(node.Nodes);
            }
            catch(Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }

        private void mainForm_Load(object sender, EventArgs e)
        {
            refreshServer();
            serverTreeView.SelectedNode = null;
        }

        private void m_server_edit_Click(object sender, EventArgs e)
        {
            if (serverTreeView.SelectedNode != null)
            {
                string name = serverTreeView.SelectedNode.Name;
                ServerConfig dialog = new ServerConfig();
                dialog.Text = "编辑服务器";
                dialog.tb_name.Text = name;
                dialog.tb_host.Text = ini.get(name, "host");
                dialog.tb_port.Value = ini.getInt(name, "port");
                dialog.tb_password.Text = ini.get(name, "password");
                dialog.cb_keyEncoding.Text = ini.get(name, "keyEncoding");
                if (!String.IsNullOrEmpty(dialog.tb_password.Text))
                    dialog.tb_password.UseSystemPasswordChar = true;
                else
                    dialog.tb_password.UseSystemPasswordChar = false;
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    name=dialog.tb_name.Text.Trim();
                    if (name == serverTreeView.SelectedNode.Name || ini.renameSection(serverTreeView.SelectedNode.Name,name))
                    {
                        ini.set(name, "host", dialog.tb_host.Text);
                        ini.set(name, "port", dialog.tb_port.Value);
                        ini.set(name, "keyEncoding", dialog.cb_keyEncoding.Text);
                        if(String.IsNullOrEmpty(dialog.tb_password.Text))
                            ini.set(name,"password",null);
                        else if (!dialog.tb_password.UseSystemPasswordChar)
                        {
                            ini.set(name, "password", AESKit.Encrypt(dialog.tb_password.Text, aesKey));
                        }
                        ini.save();
                        serverTreeView.SelectedNode.Name = serverTreeView.SelectedNode.Text = name;
                    }
                    else
                        MessageBox.Show("该服务器名已经存在！","错误",MessageBoxButtons.OK,MessageBoxIcon.Error);
                }
            }
        }

        private void m_server_new_Click(object sender, EventArgs e)
        {
            ServerConfig dialog = new ServerConfig();
            dialog.Text = "新建服务器";
            dialog.tb_name.Text = "";
            dialog.tb_host.Text = "";
            dialog.tb_port.Value = 6379;
            dialog.tb_password.Text = "";
            dialog.cb_keyEncoding.Text = "UTF-8";
            dialog.tb_password.UseSystemPasswordChar = false;
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                string name = dialog.tb_name.Text.Trim();
                if (!ini.containsSection(name))
                {
                    TreeNode node = new TreeNode();
                    node.Name = node.Text = name;
                    node.ImageKey = node.SelectedImageKey = "server";
                    serverTreeView.Nodes.Add(node);
                    serverTreeView.SelectedNode = node;

                    ini.set(name, "host", dialog.tb_host.Text);
                    ini.set(name, "port", dialog.tb_port.Value);
                    ini.set(name, "keyEncoding", dialog.cb_keyEncoding.Text);
                    if (String.IsNullOrEmpty(dialog.tb_password.Text))
                        ini.set(name, "password", null);
                    else
                    {
                        ini.set(name, "password", AESKit.Encrypt(dialog.tb_password.Text, aesKey));
                    }
                    ini.save();

                    serverTreeView.SelectedNode.Name = serverTreeView.SelectedNode.Text = name;
                }
                else
                    MessageBox.Show("该服务器名已经存在！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void mc_server_remove_Click(object sender, EventArgs e)
        {
            if (serverTreeView.SelectedNode != null 
                && MessageBox.Show("确定要删除" + serverTreeView.SelectedNode.Name+"吗？", "确认",MessageBoxButtons.OKCancel) == DialogResult.OK)
            {
                if(ini.removeSection(serverTreeView.SelectedNode.Name))
                    ini.save();
                serverTreeView.Nodes.Remove(serverTreeView.SelectedNode);
                serverTreeView.SelectedNode = null;
                enableMenu(false);
            }
        }

        private void mainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            foreach(TreeNode node in serverTreeView.Nodes)
            {
                if (node.Tag != null)
                {
                    ((Server)node.Tag).close();
                    node.Tag = null;
                }
            }
        }

        private void m_quit_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void serverMenu_Opening(object sender, CancelEventArgs e)
        {
            enableMenu(serverTreeView.SelectedNode != null);
        }

        private void m_server_DropDownOpening(object sender, EventArgs e)
        {
            enableMenu(serverTreeView.SelectedNode != null);
        }


        private void serverTreeView_MouseDown(object sender, MouseEventArgs e)
        {
            TreeNode node = serverTreeView.GetNodeAt(e.X, e.Y) as TreeNode;
            serverTreeView.SelectedNode = node;
        }

        private void serverTreeView_DoubleClick(object sender, EventArgs e)
        {
            if(serverTreeView.SelectedNode!=null)
            {
                if (serverTreeView.SelectedNode.Tag==null)
                {
                    connectServer(serverTreeView.SelectedNode);
                }
            }
        }

        private void dofragNodeList(TreeNode parent,List<TreeNode> list)
        {
            for (int i = 0; i < list.Count; i++)
            {
                int idx = list[i].Text.IndexOf(':');
                if (idx >= 0)
                {
                    string name = list[i].Text.Substring(0, idx);
                    TreeNode node = new TreeNode();
                    node.Name = node.Text = name;
                    node.SelectedImageKey = node.ImageKey = "folder";

                    list[i].Text = list[i].Text.Substring(idx + 1);
                    List<TreeNode> li = new List<TreeNode>();
                    li.Add(list[i++]);

                    for (; i < list.Count;)
                    {
                        idx = list[i].Text.IndexOf(':');
                        if (idx >= 0)
                        {
                            name = list[i].Text.Substring(0, idx);
                            if (name == node.Text)
                            {
                                list[i].Text = list[i].Text.Substring(idx + 1);
                                li.Add(list[i++]);
                            }
                            else
                                break;
                        }
                        else
                            break;
                    }
                    //删除个
                    i = i - li.Count;
                    list.RemoveRange(i, li.Count);
                    dofragNodeList(node,li);
                    list.Insert(i, node);
                    if (parent != null)
                    {
                        parent.Nodes.Insert(i, node);
                    }
                }
            }
            if (parent != null)
            {
                parent.Nodes.Clear();
                foreach (TreeNode n in list)
                    parent.Nodes.Add(n);
            }
        }

        private void RefreshDbKey(TreeNode db_node)
        {
            db_node.Nodes.Clear();
            ServerDb db = db_node.Tag as ServerDb;
            List<TreeNode> nodes = new List<TreeNode>();
            Encoding encoding = Encoding.GetEncoding(db.encoding);
            if (encoding == null) encoding = Encoding.UTF8;

            db.SureDb();
            byte[][] data = db.client.Keys("*");

            string[] keys = new string[data.Length];
            for (int j = 0; j < data.Length; j++)
                keys[j] = encoding.GetString(data[j]);
            Array.Sort(keys);

            for (int j = 0; j < keys.Length; j++)
            {
                ServerKey key = new ServerKey(db);
                key.db = db.db;
                key.key = keys[j];
                key.type = db.client.Type(key.key);
                TreeNode n = new TreeNode();
                n.Tag = key;
                n.Name = n.Text = key.key;
                n.ImageKey = n.SelectedImageKey = key.type;
                nodes.Add(n);
            }
            dofragNodeList(db_node, nodes);
        }


        private void serverTreeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            TreeNode node = e.Node as TreeNode;
            if(node!=null)
            {

            }
        }
    }
}
